package com.example.redissondemo.util;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 引擎调用工具栏
 *
 * @author yetao
 * @date 2024/3/14 17:24
 */
@Slf4j
@Component
public class LockUtil {

    private static RedissonClient redissonClient;
    private static RedisTemplate<String, Object> redisTemplate;

    @Resource
    public void setRedissonClient(RedissonClient redissonClient) {
        LockUtil.redissonClient = redissonClient;
    }

    @Resource
    public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
        LockUtil.redisTemplate = redisTemplate;
    }

    /**
     * 获取锁
     */
    public static RLock getLock(String lockKey) {
        return redissonClient.getLock(lockKey);
    }

    /**
     * 加锁操作
     *
     * @return 返回值 boolean
     */
    public static boolean tryLock(String lockName, long expireSeconds) {
        return tryLock(lockName, 0, expireSeconds);
    }


    /**
     * 加锁操作
     *
     * @return 返回值 boolean
     */
    public static boolean tryLock(String lockName, long waitTime, long expireSeconds) {
        RLock rLock = getLock(lockName);
        boolean getLock = false;
        try {
            getLock = rLock.tryLock(waitTime, expireSeconds, TimeUnit.SECONDS);
            if (getLock) {
                log.info("lock success, lockName:[{}]", lockName);
            } else {
                log.info("lock fail, lockName:[{}]", lockName);
            }
        } catch (InterruptedException e) {
            log.error("lock error，lockName:[{}]", lockName, e);
        }
        return getLock;
    }


    public static boolean fairLock(String lockKey, TimeUnit unit, int leaseTime) {
        RLock fairLock = redissonClient.getFairLock(lockKey);
        try {
            boolean existKey = existKey(lockKey);
            // 已经存在了，就直接返回
            if (existKey) {
                return false;
            }
            return fairLock.tryLock(3, leaseTime, unit);
        } catch (InterruptedException e) {
            log.error("lock error, lockName:[{}]", lockKey, e);
        }
        return false;
    }

    public static boolean existKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 锁lockKey
     *
     * @param lockKey 锁名
     * @return 返回值
     */
    public static RLock lock(String lockKey) {
        RLock lock = getLock(lockKey);
        lock.lock();
        return lock;
    }

    /**
     * 锁lockKey
     *
     * @param lockKey   锁名
     * @param leaseTime 释放时间
     * @return 返回值
     */
    public static RLock lock(String lockKey, long leaseTime) {
        RLock lock = getLock(lockKey);
        lock.lock(leaseTime, TimeUnit.SECONDS);
        return lock;
    }


    /**
     * 解锁
     *
     * @param lockName 锁名称
     */
    public static void unlock(String lockName) {
        try {
            RLock lock = redissonClient.getLock(lockName);
            // 是否还是锁定状态
            if(lock.isLocked()) {
                // 时候是当前执行线程的锁
                if (lock.isHeldByCurrentThread()) {
                    // 释放锁
                    lock.unlock();
                }
            }
            log.info("unlock，lockName:[{}]", lockName);
        } catch (Exception e) {
            log.error("unlock，lockName:[{}]", lockName, e);
        }
    }


}
